package com.meida.common.interceptor;

import com.meida.common.annotation.RLock;
import com.meida.common.lock.RedissonLocker;
import com.meida.common.mybatis.entity.EntityMap;
import com.meida.common.utils.FlymeUtils;
import com.meida.common.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * @Author:yexg
 * @Date:2019-07-31 10:52
 * @Description: redis锁切面
 **/
@Aspect
@Component
public class LockAspectJ {
    @Autowired
    private RedissonLocker redisLock;

    /**
     * 声明一个切入点（包括切入点表达式和切入点签名）
     */
    @Pointcut("@annotation(com.meida.common.annotation.RLock)")
    public void anyMethod() {
    }

    /***********切面加锁*****/
    @Around("anyMethod()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object[] ojs = point.getArgs();
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();
        RLock lock = method.getAnnotation(RLock.class);
        if (FlymeUtils.isEmpty(lock)) {
            return point.proceed();
        }
        String key = lock.value();
        /******如果value不为空设置value为key****/
        if (StringUtils.isEmpty(key)) {
            key += lock.prefix();
            /*****设置参数以及前缀为key*****/
            int paramIndex = lock.paramIndex();
            if (paramIndex >= 0 && paramIndex < ojs.length) {
                Object value = ojs[paramIndex];
                if (value != null) {
                    key += value.toString();
                }
            }
            String[] paramNames = lock.paramName();
            if (FlymeUtils.isNotEmpty(paramNames)) {
                if (FlymeUtils.isNotEmpty(ojs[0])) {
                    Map<String, Object> map = (Map<String, Object>) ojs[0];
                    if (FlymeUtils.isNotEmpty(map) && FlymeUtils.isNotEmpty(map.get("params"))) {
                        map.putAll(JsonUtils.jsonToBean(map.get("params").toString(), EntityMap.class));
                    }
                    for (String paramName : paramNames) {
                        key += map.get(paramName);
                    }
                }
            }
        }
        /***如果key为空不加锁**/
        if (StringUtils.isEmpty(key)) {
            return point.proceed();
        }
        /******加锁****/
        org.redisson.api.RLock lockValue = redisLock.lock(key);
        try {
            return point.proceed();
        } finally {
            redisLock.unlock(lockValue);
        }
    }
}
